using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Timers;
using System.Windows.Forms;
using System.Xml;
using Client.CCS;
using Client.Properties;
using Timer=System.Timers.Timer;

//[assembly: AssemblyDelaySign(true)]
//[assembly: AssemblyKeyFile("PublicKeyFile.snk")]

namespace Client.UIHelper
{
    public class ProcessingFailedEvent : EventArgs
    {
        private Exception exception;
        private FailureInfo failureInfo;
        private Form formReference;
        private string message;

        public ProcessingFailedEvent()
        {
        }

        public ProcessingFailedEvent(string str, Form form)
        {
            message = str;
            formReference = form;
        }

        public ProcessingFailedEvent(FailureInfo failure, Form form)
        {
            failureInfo = failure;
            formReference = form;
        }

        public ProcessingFailedEvent(FailureInfo failure)
        {
            failureInfo = failure;
        }

        public ProcessingFailedEvent(Exception ex)
        {
            exception = ex;
        }

        public FailureInfo FailureInformation
        {
            get { return failureInfo; }
            set { failureInfo = value; }
        }

        public string Message
        {
            get { return message; }
        }

        public Form FormReference
        {
            get { return formReference; }
        }

        public Exception FailureException
        {
            get { return exception; }
        }
    }

    public class ProcessingCompletedEvent : EventArgs
    {
        private object _object;
        private Form formReference;
        private string message;

        public ProcessingCompletedEvent()
        {
        }

        public ProcessingCompletedEvent(object argsObject)
        {
            _object = argsObject;
        }

        public ProcessingCompletedEvent(string str, Form form)
        {
            message = str;
            formReference = form;
        }

        public string Message
        {
            get { return message; }
        }

        public Form FormReference
        {
            get { return formReference; }
        }

        public Object ArgsObject
        {
            get { return _object; }
        }
    }

    public delegate void MarshallThisFuncString(string s);

    public delegate DialogResult MarshallthisFuncString_RetDR(string s);

    public delegate void MarshallThisFuncFailureInfo(FailureInfo f);

    /// <summary>
    /// Implements the layer of the CCS that is used to communicate
    /// with the Shareware Server.  It's called by the UI layer which is
    /// either the RegisterForm, ActivateNowHelper, and the BuyNowHelper.
    /// </summary>
    public class Serverprocessing : IDisposable
    {
        #region Private variables

        //initialize the logger
        // Keeps track of the number of times the BuyNow polling has timed out
        private object _info;
        private EventHandler<ProcessingCompletedEvent> _processingcomplete;
        private EventHandler<ProcessingFailedEvent> _processingfailed;
        private int _timerCount;
        // How often we poll
        // How much time to elapse before aborting an async Web Method
        private Timer abortTimer = new Timer();
        private bool formClosed = false;
        private Logger logger = new Logger(Application.StartupPath, "CCSClientLog.txt");
        // Object which manages the License Store
        private DataStore m_datastore;
        private CCS.CCS m_webservice = new CCS.CCS();
        private Timer pollingTimer = new Timer();

        // Tracks whether there is an Async Web Service method 
        // currently in progress.
        private bool wsInProgress = false;

        //used to ignore multiple returned results from the web service
        private bool wsResultReceived = false;

        //keeps track of if the form that initially made the web service request
        //is open or closed

        #endregion

        #region Public event handlers

        /// <summary>
        /// Handles Events that are used by the UI layer to signal a successful
        /// completion for the Serverprocessing class.
        /// </summary>
        public EventHandler<ProcessingCompletedEvent> Processingcomplete
        {
            get { return _processingcomplete; }
            set { _processingcomplete = value; }
        }

        /// <summary>
        /// Handles Events that are used by the UI layer to signal a failed
        /// completion for the Serverprocessing class.  The failure message
        /// is passed pack in the event args.
        /// </summary>
        public EventHandler<ProcessingFailedEvent> Processingfailed
        {
            get { return _processingfailed; }
            set { _processingfailed = value; }
        }

        #endregion

        #region Constructors

        public Serverprocessing(DataStoreInfo dsInfo)
        {
            Logger.Log("ServerProcessing : Constructor (DataStoreInfo) : Beginning");
            m_webservice.UseDefaultCredentials = true;

            _info = dsInfo;
            Logger.Log("ServerProcessing : Constructor (DataStoreInfo) : Completed");
        }

        public Serverprocessing(FeedbackInfo fbInfo)
        {
            Logger.Log("ServerProcessing : Constructor (FeedbackInfo) : Beginning");
            m_datastore = new DataStore(fbInfo.FormRef);
            m_webservice.UseDefaultCredentials = true;

            abortTimer.Interval = m_datastore.AbortTimerLength;
            abortTimer.AutoReset = false;
            abortTimer.Elapsed += new ElapsedEventHandler(abortTimer_Elapsed);

            _info = fbInfo;
            Logger.Log("ServerProcessing : Constructor (FeedbackInfo) : Completed");
        }

        public Serverprocessing(ExceptionInfo eInfo)
        {
            Logger.Log("ServerProcessing : Constructor (ExceptionInfo) : Beginning");
            m_datastore = new DataStore(eInfo.FormRef);
            m_webservice.UseDefaultCredentials = true;

            abortTimer.Interval = m_datastore.AbortTimerLength;
            abortTimer.AutoReset = false;
            abortTimer.Elapsed += new ElapsedEventHandler(abortTimer_Elapsed);

            _info = eInfo;
            Logger.Log("ServerProcessing : Constructor (ExceptionInfo) : Completed");
        }

        public Serverprocessing(RegisterInfo rInfo)
        {
            Logger.Log("ServerProcessing : Constructor (RegisterInfo) : Beginning");
            m_datastore = new DataStore(rInfo.FormRef);
            m_webservice.UseDefaultCredentials = true;

            abortTimer.Interval = m_datastore.AbortTimerLength;
            abortTimer.AutoReset = false;
            abortTimer.Elapsed += new ElapsedEventHandler(abortTimer_Elapsed);

            _info = rInfo;
            Logger.Log("ServerProcessing : Constructor (RegisterInfo) : Completed");
        }

        public Serverprocessing(BuyNowInfo bnInfo)
        {
#if DEBUG
            m_webservice.CreateTestData(Settings.Default.PaymentNotifyURL, Settings.Default.PaymentURL);
#endif

            Logger.Log("ServerProcessing : Constructor (BuyNowInfo) : Beginning");
            m_datastore = new DataStore(bnInfo.FormRef);
            m_webservice.UseDefaultCredentials = true;

            pollingTimer.Interval = m_datastore.PollingTimerLength;
            pollingTimer.AutoReset = true;

            abortTimer.Interval = m_datastore.AbortTimerLength;
            abortTimer.AutoReset = false;
            abortTimer.Elapsed += new ElapsedEventHandler(abortTimer_Elapsed);

            _info = bnInfo;
            Logger.Log("ServerProcessing : Constructor (BuyNowInfo) : Completed");
        }

        #endregion

        #region Web Service event handlers

        /// <summary>
        /// Web service event handler for submit exception
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void _webservice_SubmitExceptionCompleted(object sender, SubmitExceptionCompletedEventArgs args)
        {
            Logger.Log("ServerProcessing : _webservice_SubmitExceptionCompleted");
            HandleSubmitExceptionCompleted(args);
        }

        /// <summary>
        /// Web service event handler for issue/feedback submission
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void _webservice_SubmitIssueCompleted(object sender, SubmitIssueCompletedEventArgs args)
        {
            Logger.Log("ServerProcessing : _webservice_SubmitIssueCompleted");
            HandleSubmitIssueCompleted(args);
        }

        /// <summary>
        /// Web service event handler for user registration
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void _webservice_RegisterUserCompleted(object sender, RegisterUserCompletedEventArgs args)
        {
            Logger.Log("ServerProcessing : _webservice_RegisterUserCompleted");
            HandleRegisterUserCompleted(args);
        }

        /// <summary>
        /// Web service event handler for obtaining client application configuration data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void _webservice_GetClientAppConfigCompleted(object sender, GetClientAppConfigCompletedEventArgs args)
        {
            Logger.Log("ServerProcessing : _webservice_GetClientAppConfigCompleted");
            HandleGetClientAppConfigCompleted((GetClientAppConfigCompletedEventArgs) args);
        }

        /// <summary>
        /// Web service event handler for getting a license.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void _webservice_GetLicenseCompleted(object sender, GetLicenseCompletedEventArgs args)
        {
            Logger.Log("ServerProcessing : _webservice_GetLicenseCompleted");
            HandleGetLicenseCompleted((GetLicenseCompletedEventArgs) args);
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        public void HandleRegistration()
        {
            Logger.Log("ServerProcessing : HandleRegistration : Beginning");
            var registerInfo = (RegisterInfo) _info;

            m_webservice.RegisterUserCompleted += new RegisterUserCompletedEventHandler(_webservice_RegisterUserCompleted);
            m_webservice.RegisterUserAsync(registerInfo.LastName, registerInfo.FirstName, registerInfo.Address, registerInfo.City, registerInfo.State, registerInfo.Zipcode, registerInfo.Phone, registerInfo.Email, registerInfo.DevToken, registerInfo.ProductName, m_datastore.UniqueMachineID, registerInfo.LicenseLevel);

            //start the abort timer to catch delayed responses from the web server.
            abortTimer.Start();

            Logger.Log("ServerProcessing : HandleRegistration : Completed");
        }

        public void HandleFeedback()
        {
            Logger.Log("ServerProcessing : HandleFeedback : Beginning");

            var feedbackInfo = (FeedbackInfo) _info;

            m_webservice.SubmitIssueCompleted += new SubmitIssueCompletedEventHandler(_webservice_SubmitIssueCompleted);
            m_webservice.SubmitIssueAsync(feedbackInfo.ProductName, feedbackInfo.LicenseLevel, feedbackInfo.Email, feedbackInfo.FirstName, feedbackInfo.LastName, feedbackInfo.Description, feedbackInfo.DevToken, m_datastore.UniqueMachineID);

            //start the abort timer to catch delayed responses from the web server.
            abortTimer.Start();

            Logger.Log("ServerProcessing : HandleFeedback : Completed");
        }

        public void HandleException()
        {
            Logger.Log("ServerProcessing : HandleException : Beginning");
            var exceptionInfo = (ExceptionInfo) _info;

            m_webservice.SubmitExceptionCompleted += new SubmitExceptionCompletedEventHandler(_webservice_SubmitExceptionCompleted);
            m_webservice.SubmitExceptionAsync(exceptionInfo.Message, exceptionInfo.Source, exceptionInfo.StackTrace, exceptionInfo.MethodName, exceptionInfo.ProductName, exceptionInfo.DevToken, m_datastore.UniqueMachineID, exceptionInfo.LicenseLevel);

            //start the abort timer to catch delayed responses from the web server.
            abortTimer.Start();

            Logger.Log("ServerProcessing : HandleException : Completed");
        }

        public void HandleBuyNow()
        {
            Logger.Log("ServerProcessing : HandleBuyNow : Beginning");

            pollingTimer.Elapsed += new ElapsedEventHandler(pollingTimer_Elapsed);
            Logger.Log("ServerProcessing : HandleProcessing : Polling Timer =" + pollingTimer.Interval.ToString() + " ms");
            pollingTimer.Start();

            Logger.Log("ServerProcessing : HandleBuyNow : Completed");
        }

        /// <summary>
        /// Start a transmission to the web service to get the DefaultStorage();
        /// </summary>
        public ClientAppConfig ContactServerForDefaultStorage(DataStoreInfo dataStoreInfo)
        {
            Logger.Log("ServerProcessing : ContactServerForDefaultStorage : Beginning");
            Logger.Log("ServerProcessing : ContactServerForDefaultStorage : WsInProgress : " + wsInProgress.ToString());

            //If we are getting a new datastore and config settings from the server
            return m_webservice.GetClientAppConfig(dataStoreInfo.ProductName, dataStoreInfo.DevId, dataStoreInfo.UniqueClientId, dataStoreInfo.StartDateTime);
        }

        /// <summary>
        /// Start the transmission to the web service.
        /// </summary>
        private void ContactServerForLicensingInfo()
        {
            Logger.Log("ServerProcessing : ContactServerForLicensingInfo : Beginning");
            Logger.Log("ServerProcessing : ContactServerForLicensingInfo : WsInProgress : " + wsInProgress.ToString());

            wsInProgress = true;

            var buyNowInfo = (BuyNowInfo) _info;

            m_webservice.GetLicenseCompleted += new GetLicenseCompletedEventHandler(_webservice_GetLicenseCompleted);
            m_webservice.GetLicenseAsync(Settings.Default.ProductName, m_datastore.UniqueMachineID, buyNowInfo.LicenseLevel, buyNowInfo.Invoice, Settings.Default.DevToken, m_datastore.UniqueMachineID);

            //start the abort timer to catch delayed responses from the web server.
            abortTimer.Start();

            Logger.Log("ServerProcessing : ContactServerForLicensingInfo : Completed");
        }


        /// <summary>
        /// Handle the client app config completed request received from the webservice
        /// </summary>
        /// <param name="eventArgs"></param>
        private void HandleSubmitExceptionCompleted(SubmitExceptionCompletedEventArgs submitExceptionArgs)
        {
            Logger.Log("ServerProcessing::HandleSubmitExceptionCompleted - Beginning");

            abortTimer.Stop();

            var exceptionInfo = (ExceptionInfo) _info;
            if (!formClosed)
            {
                if (submitExceptionArgs.Cancelled)
                {
                    Logger.Log("ServerProcessing : HandleSubmitExceptionCompleted : Web service was cancelled");
                    FailureInfo cancelledInfo = HandleWebServiceCancelled(submitExceptionArgs);
                    Processingfailed(this, new ProcessingFailedEvent(cancelledInfo, exceptionInfo.FormRef));
                }
                else if (submitExceptionArgs.Error != null)
                {
                    Logger.Log("ServerProcessing : HandleSubmitExceptionCompleted : Error : " + CrackReason(submitExceptionArgs.Error));
                    FailureInfo failedInfo = HandleWebServiceException(submitExceptionArgs.Error);
                    Processingfailed(this, new ProcessingFailedEvent(failedInfo, exceptionInfo.FormRef));
                }
                else if (submitExceptionArgs.Result)
                {
                    Logger.Log("ServerProcessing : HandleSubmitExceptionCompleted : Success");
                    string message = "Your error information was successfully submitted.";
                    Processingcomplete(this, new ProcessingCompletedEvent(message, exceptionInfo.FormRef));
                }
                else
                {
                    Logger.Log("ServerProcessing : HandleSubmitExceptionCompleted : Failed");
                    var failureInfo = new FailureInfo();
                    failureInfo.Message = "There was an error processing your exception submission.";
                    failureInfo.Alert = FailureInfo.AlertType.None;
                    Processingfailed(this, new ProcessingFailedEvent(failureInfo, exceptionInfo.FormRef));
                }
            }

            Logger.Log("ServerProcessing::HandleSubmitExceptionCompleted - End");
        }

        /// <summary>
        /// Handle the client app config completed request received from the webservice
        /// </summary>
        /// <param name="eventArgs"></param>
        private void HandleSubmitIssueCompleted(SubmitIssueCompletedEventArgs submitIssueArgs)
        {
            Logger.Log("ServerProcessing::HandleSubmitIssueCompleted - Beginning");

            abortTimer.Stop();

            var feedbackInfo = (FeedbackInfo) _info;
            if (!formClosed)
            {
                if (submitIssueArgs.Cancelled)
                {
                    Logger.Log("ServerProcessing : HandleSubmitIssueCompleted : Web service was cancelled");
                    FailureInfo cancelledInfo = HandleWebServiceCancelled(submitIssueArgs);
                    Processingfailed(this, new ProcessingFailedEvent(cancelledInfo, feedbackInfo.FormRef));
                }
                else if (submitIssueArgs.Error != null)
                {
                    Logger.Log("ServerProcessing : HandleSubmitIssueCompleted : Error : " + CrackReason(submitIssueArgs.Error));
                    FailureInfo failedInfo = HandleWebServiceException(submitIssueArgs.Error);
                    Processingfailed(this, new ProcessingFailedEvent(failedInfo, feedbackInfo.FormRef));
                }
                else if (submitIssueArgs.Result)
                {
                    Logger.Log("ServerProcessing : HandleSubmitIssueCompleted : Success");
                    string message = "Your feedback was successfully submitted.";
                    Processingcomplete(this, new ProcessingCompletedEvent(message, feedbackInfo.FormRef));
                }
                else
                {
                    Logger.Log("ServerProcessing : HandleSubmitIssueCompleted : Failed");
                    var failureInfo = new FailureInfo();
                    failureInfo.Message = "There was an error processing your feedback submission";
                    failureInfo.Alert = FailureInfo.AlertType.None;
                    Processingfailed(this, new ProcessingFailedEvent(failureInfo, feedbackInfo.FormRef));
                }
            }

            Logger.Log("ServerProcessing::HandleSubmitIssueCompleted - End");
        }

        /// <summary>
        /// Handle the client app config completed request received from the webservice
        /// </summary>
        /// <param name="eventArgs"></param>
        private void HandleRegisterUserCompleted(RegisterUserCompletedEventArgs registerArgs)
        {
            Logger.Log("ServerProcessing::HandleRegisterUserCompleted - Beginning");

            abortTimer.Stop();

            var registerInfo = (RegisterInfo) _info;
            if (!formClosed)
            {
                if (registerArgs.Cancelled)
                {
                    Logger.Log("ServerProcessing : HandleRegisterUserCompleted : Registration Web service was cancelled");
                    FailureInfo cancelledInfo = HandleWebServiceCancelled(registerArgs);
                    Processingfailed(this, new ProcessingFailedEvent(cancelledInfo, registerInfo.FormRef));
                }
                else if (registerArgs.Error != null)
                {
                    Logger.Log("ServerProcessing : HandleRegisterUserCompleted : Registration error : " + CrackReason(registerArgs.Error));
                    FailureInfo failedInfo = HandleWebServiceException(registerArgs.Error);
                    Processingfailed(this, new ProcessingFailedEvent(failedInfo, registerInfo.FormRef));
                }
                else if (registerArgs.Result)
                {
                    Logger.Log("ServerProcessing : HandleRegisterUserCompleted : Success");

                    string message = "Your registration was successful.";
                    m_datastore.UserRegistered = true;
                    Processingcomplete(this, new ProcessingCompletedEvent(message, registerInfo.FormRef));
                }
                else
                {
                    Logger.Log("ServerProcessing : HandleRegisterUserCompleted : Failed");
                    var failureInfo = new FailureInfo();
                    failureInfo.Message = "There was an error processing your registration request.";
                    failureInfo.Alert = FailureInfo.AlertType.None;
                    Processingfailed(this, new ProcessingFailedEvent(failureInfo, registerInfo.FormRef));
                }
            }

            Logger.Log("ServerProcessing::HandleRegisterUserCompleted - End");
        }

        /// <summary>
        /// Handle the client app config completed request received from the webservice
        /// </summary>
        /// <param name="eventArgs"></param>
        private void HandleGetClientAppConfigCompleted(GetClientAppConfigCompletedEventArgs clientAppConfigArgs)
        {
            Logger.Log("ServerProcessing::HandleGetClientAppConfigCompleted - Beginning");

            abortTimer.Stop();

            var dsi = (DataStoreInfo) _info;
            if (clientAppConfigArgs.Cancelled)
            {
                Logger.Log("ServerProcessing : HandleGetClientAppConfigCompleted : Web service was cancelled");
                FailureInfo cancelledInfo = HandleWebServiceCancelled(clientAppConfigArgs);
                Processingfailed(this, new ProcessingFailedEvent(cancelledInfo, dsi.FormRef));
            }
            else if (clientAppConfigArgs.Error != null)
            {
                Logger.Log("ServerProcessing : HandleGetClientAppConfigCompleted : Error : " + clientAppConfigArgs.Error.Message);
                FailureInfo failedInfo = HandleWebServiceException(clientAppConfigArgs.Error);
                Processingfailed(this, new ProcessingFailedEvent(failedInfo, dsi.FormRef));
            }
            else if (clientAppConfigArgs.Result != null)
            {
                Logger.Log("ServerProcessing : HandleGetClientAppConfigCompleted : Success");
                Processingcomplete(this, new ProcessingCompletedEvent(clientAppConfigArgs.Result));
            }
            else
            {
                Logger.Log("ServerProcessing : HandleGetClientAppConfigCompleted : Failed");
                var failureInfo = new FailureInfo();
                failureInfo.Message = "There was a problem obtaining the configuration settings from the seb service.";
                failureInfo.Alert = FailureInfo.AlertType.None;
                Processingfailed(this, new ProcessingFailedEvent(failureInfo, dsi.FormRef));
            }

            Logger.Log("ServerProcessing::HandleGetClientAppConfigCompleted - End");
        }

        /// <summary>
        /// Handle the client app config completed request received from the webservice
        /// </summary>
        /// <param name="eventArgs"></param>
        private void HandleGetLicenseCompleted(GetLicenseCompletedEventArgs licenseArgs)
        {
            Logger.Log("ServerProcessing::HandleGetLicenseCompleted - Beginning");

            abortTimer.Stop();
            pollingTimer.Stop();

            wsInProgress = false;

            // if we are already processing a complete, just bail.
            if (wsResultReceived)
                return;

            wsResultReceived = true;

            var bni = (BuyNowInfo) _info;
            if (!formClosed)
            {
                if (licenseArgs.Cancelled)
                {
                    Logger.Log("ServerProcessing : HandleGetLicenseCompleted : get license Web service was cancelled");
                    FailureInfo cancelledInfo = HandleWebServiceCancelled(licenseArgs);
                    Processingfailed(this, new ProcessingFailedEvent(cancelledInfo, bni.FormRef));
                }
                else if (licenseArgs.Error != null)
                {
                    Logger.Log("ServerProcessing : HandleGetLicenseCompleted : get license Web service error: " + CrackReason(licenseArgs.Error));
                    FailureInfo failedInfo = HandleWebServiceException(licenseArgs.Error);
                    Processingfailed(this, new ProcessingFailedEvent(failedInfo, bni.FormRef));
                }
                else if (licenseArgs.Result != null)
                {
                    Logger.Log("ServerProcessing : HandleGetLicenseCompleted :  get license Web service result received");

                    var result = new XmlDocument();
                    result.LoadXml(licenseArgs.Result);
                    //if (_ds.SetRegistrationKey(Convert.ToBase64String(result.SelectSingleNode("//AuthenticatedLicense")), result.SelectSingleNode("//LicenseLevel")))
                    if (m_datastore.SetRegistrationKey(result.SelectSingleNode("//AuthenticatedLicense").InnerText, result.SelectSingleNode("//LicenseLevel").InnerText))
                    {
                        Logger.Log("ServerProcessing : HandleGetLicenseCompleted :  Set License Key Successful");
                        string message = "Activation Complete!  Please click below to register.";
                        Processingcomplete(this, new ProcessingCompletedEvent(message, bni.FormRef));
                    }
                    else
                    {
                        Logger.Log("ServerProcessing : HandleGetLicenseCompleted :  Set License Key Failed");
                        var failureInfo = new FailureInfo();
                        failureInfo.Message = "License response received from web service is invalid.  Please verify the server configuration.";
                        failureInfo.Alert = FailureInfo.AlertType.None;
                        Processingfailed(this, new ProcessingFailedEvent(failureInfo, bni.FormRef));
                    }
                }
                else if (licenseArgs.Result == null)
                {
                    Logger.Log("ServerProcessing : HandleGetLicenseCompleted : Null Result Received");
                    pollingTimer.Start();
                    Logger.Log("ServerProcessing : HandleGetLicenseCompleted : Polling Timer Started");
                    wsResultReceived = false;
                    Logger.Log("ServerProcessing : HandleGetLicenseCompleted : wsResultReceived = false");
                }
            }

            Logger.Log("ServerProcessing::HandleGetLicenseCompleted - End");
        }

        private FailureInfo HandleWebServiceCancelled(Object args)
        {
            var failureInfo = new FailureInfo();

            failureInfo.Message = "An error occurred while contacting the web service. ";
            failureInfo.Message += "The server did not respond in a timely manner.  Please verify your internet ";
            failureInfo.Message += "connection and try again.";

            return failureInfo;
        }

        private FailureInfo HandleWebServiceException(Exception ex)
        {
            var failureInfo = new FailureInfo();

            failureInfo.Message = CrackReason(ex);
            if (ex.InnerException != null)
            {
                if (ex.InnerException.GetType() == typeof (SocketException))
                {
                    failureInfo.Message = failureInfo.Message + " Please verify the following " + "URL is available using internet explorer: " + Settings.Default.Client_CCSWebService;
                    failureInfo.Alert = FailureInfo.AlertType.Port;
                }
                else
                {
                    failureInfo.Alert = FailureInfo.AlertType.None;
                }
            }
            else
            {
                failureInfo.Alert = FailureInfo.AlertType.None;
            }

            return failureInfo;
        }

        /// <summary>
        /// Looks inside an exception thrown at the CCS Server for
        /// the reason why the exception was thrown.
        /// </summary>
        /// <param name="message"></param>
        /// <returns>A string containing the reason message.</returns>
        private static string CrackReason(Exception exception)
        {
            string userMessage;

            Logger.Log("ServerProcessing : CrackReason : Crack Reason Raw Message : " + exception.Message);

            if (exception.GetType() == typeof (SocketException))
            {
                string message = "There was an error contacting the server.  Please ensure you have ";
                message += "internet connectivity or try again later.";
                return message;
            }

            if (exception.InnerException != null)
            {
                if (exception.InnerException.GetType() == typeof (SocketException))
                {
                    string message = "There was an error contacting the server.  Please ensure you have ";
                    message += "internet connectivity or try again later.";
                    return message;
                }
            }

            int startPos = exception.Message.IndexOf("Reason: '");


            startPos += 9;

            int endPos = exception.Message.IndexOf("'", startPos);

            if (endPos > 0)
            {
                userMessage = exception.Message.Substring(startPos, endPos - startPos);
            }
            else
            {
                userMessage = "An unknown error occurred while contacting the server." + exception.Message;
            }
            Logger.Log("ServerProcessing : CrackReason : Crack Reason User Message : " + userMessage + " : Exception : " + exception.Message);

            return userMessage;
        }

        /// <summary>
        /// Called by a UI helper class to stop a Web Service in situations
        /// where the polling/abort system needs to be stopped.  This might
        /// happen inside a BeginXXX and EndXXX call which means that 
        /// we need to cancel the Async Web Service call.
        /// </summary>
        public void Cancelprocessing()
        {
            Logger.Log("ServerProcessing : Cancelprocessing : Beginning");

            pollingTimer.Stop();
            formClosed = true;
            Logger.Log("ServerProcessing : Cancelprocessing : Polling timer Stopped in cancel processing");

            // Make sure that we abort the call only if there is currently
            // an Async Web Service in progress.
            if (wsInProgress == true)
            {
                wsInProgress = false;
                abortTimer.Stop();

                //try to cancel the web service async call
                try
                {
                    m_webservice.CancelAsync(null);
                }
                catch (Exception)
                {
                    // Output to the debug port
                    throw;
                }
                catch
                {
                    throw;
                }
            }

            Logger.Log("ServerProcessing : Cancelprocessing : Completed");
        }

        // Implement IDispose

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Free other state (managed object)
                m_datastore.Dispose();
                pollingTimer.Dispose();
                abortTimer.Dispose();
            }
            // Free your own state (unmanaged objects)

            // Set large field to null
        }

        // Use C# destructor syntax for finalization code
        ~Serverprocessing()
        {
            Dispose(false);
        }

        #region AbortTimer code

        /// <summary>
        /// The timer callback that stops the web service calls.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void abortTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Logger.Log("ServerProcessing : abortTimer_Elapsed : Abort timer elapsed");

            m_webservice.CancelAsync(null);
        }

        #endregion

        #region Web Service Polling code

        /// <summary>
        /// This is the method that gets called when the Polling timer hits.  
        /// It starts the Buy Now and Activate Now polling sequence.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        ///
        private void pollingTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Logger.Log("ServerProcessing : pollingTimer_Elapsed : Beginning");

            int maxNumPolls = m_datastore.BuyNowMaxNumPoll;
            var buyNowInfo = (BuyNowInfo) _info;

            Logger.Log("ServerProcessing : pollingTimer_Elapsed : Timer Count:" + _timerCount.ToString() + " Max num polls:" + maxNumPolls.ToString());

            if (!wsInProgress)
            {
                if (_timerCount < maxNumPolls && !(_timerCount == 1 && buyNowInfo.IsProductKey))
                {
                    ContactServerForLicensingInfo();
                }
                else
                {
                    Logger.Log("ServerProcessing : pollingTimer_Elapsed : PollingTimer.Stop");
                    pollingTimer.Stop();


                    string message = "Sorry, your invoice is not in the database. Please try again later.";
                    Logger.Log("ServerProcessing : pollingTimer_Elapsed : max num polls exceeded");
                    var failureInfo = new FailureInfo();
                    failureInfo.Message = message;
                    failureInfo.Alert = FailureInfo.AlertType.None;
                    Processingfailed(this, new ProcessingFailedEvent(failureInfo, buyNowInfo.FormRef));
                }

                _timerCount++;
            }
            else
            {
                Logger.Log("ServerProcessing : wsinprogress = " + wsInProgress.ToString() + " Did not contact server.");
            }

            Logger.Log("ServerProcessing : pollingTimer_Elapsed : Completed");
        }

        #endregion
    }

    /// <summary>
    /// This class implements an exception which is thrown when an attempt is 
    /// made to call a web service and there is a failure.
    /// </summary>
    [Serializable]
    public class Webserviceconnectionexception : Exception
    {
        //
        // Constructors
        //

        public Webserviceconnectionexception()
        {
        }

        public Webserviceconnectionexception(string s) : base(s)
        {
        }

        public Webserviceconnectionexception(string s, Exception innerE) : base(s, innerE)
        {
        }

        protected Webserviceconnectionexception(SerializationInfo si, StreamingContext c) : base(si, c)
        {
        }
    }

    /// <summary>
    /// This class implements an exception which is thrown when web service call is cancelled.
    /// </summary>
    [Serializable]
    public class Webservicecancelledexception : Exception
    {
        //
        // Constructors
        //
        public Webservicecancelledexception()
        {
        }

        public Webservicecancelledexception(string s) : base(s)
        {
        }

        public Webservicecancelledexception(string s, Exception innerE) : base(s, innerE)
        {
        }

        protected Webservicecancelledexception(SerializationInfo si, StreamingContext c) : base(si, c)
        {
        }
    }

    /// <summary>
    /// ExceptionInfo holds all the information about an exception, and is passed into the web service processing
    /// class- ServerProcessing.
    /// </summary>
    public class ExceptionInfo
    {
        private string _devToken;
        private Form _formReference;
        private string _licenseLevel;
        private string _message;
        private string _methodname;
        private string _productname;
        private string _source;
        private string _stacktrace;
        private string _uniqueMachineID;

        public ExceptionInfo(string message, string source, string stackTrace, string methodName, string productName, string devToken, string uniqueMachineId, string licenseLevel, Form form)
        {
            _message = message;
            _source = source;
            _stacktrace = stackTrace;
            _methodname = methodName;
            _productname = productName;
            _devToken = devToken;
            _uniqueMachineID = uniqueMachineId;
            _licenseLevel = licenseLevel;
            _formReference = form;
        }

        public Form FormRef
        {
            get { return _formReference; }
        }

        public string Message
        {
            get { return _message; }
        }

        public string Source
        {
            get { return _source; }
        }

        public string StackTrace
        {
            get { return _stacktrace; }
        }

        public string MethodName
        {
            get { return _methodname; }
        }

        public string ProductName
        {
            get { return _productname; }
        }

        public string DevToken
        {
            get { return _devToken; }
        }

        public string UniqueMachineID
        {
            get { return _uniqueMachineID; }
        }

        public string LicenseLevel
        {
            get { return _licenseLevel; }
        }
    }

    /// <summary>
    /// The class containing all feedback information that is passed to the web service processing class
    /// ServerProcessing for transmission to the server.
    /// </summary>
    public class FeedbackInfo
    {
        private string _description;
        private string _devToken;
        private string _email;
        private string _firstname;
        private Form _formReference;
        private string _lastname;
        private string _licenselevel;
        private string _productname;


        public FeedbackInfo(string productName, string licenseLevel, string email, string firstName, string lastName, string description, string devtoken, Form form)
        {
            _productname = productName;
            _licenselevel = licenseLevel;
            _email = email;
            _firstname = firstName;
            _lastname = lastName;
            _description = description;
            _devToken = devtoken;
            _formReference = form;
        }

        public Form FormRef
        {
            get { return _formReference; }
        }

        public string ProductName
        {
            get { return _productname; }
        }

        public string LicenseLevel
        {
            get { return _licenselevel; }
        }

        public string Email
        {
            get { return _email; }
        }

        public string FirstName
        {
            get { return _firstname; }
        }

        public string LastName
        {
            get { return _lastname; }
        }

        public string Description
        {
            get { return _description; }
        }

        public string DevToken
        {
            get { return _devToken; }
        }
    }

    /// <summary>
    /// The class that contains all registration information to be transmitted to the server.
    /// </summary>
    public class RegisterInfo
    {
        private string _address;
        private string _city;
        private string _devToken;
        private string _email;
        private string _firstname;
        private Form _formReference;
        private string _lastname;
        private string _licenselevel;
        private string _phone;
        private string _productname;
        private string _state;
        private string _uniqueMachineID;
        private string _zipcode;


        public RegisterInfo(string productName, string licenseLevel, string email, string firstName, string lastName, string devtoken, string address, string city, string state, string zipcode, string phone, string uniqueMachineID, Form form)
        {
            _productname = productName;
            _licenselevel = licenseLevel;
            _email = email;
            _firstname = firstName;
            _lastname = lastName;
            _devToken = devtoken;
            _address = address;
            _city = city;
            _state = state;
            _zipcode = zipcode;
            _phone = phone;
            _uniqueMachineID = uniqueMachineID;
            _formReference = form;
        }

        public Form FormRef
        {
            get { return _formReference; }
        }

        public string ProductName
        {
            get { return _productname; }
        }

        public string LicenseLevel
        {
            get { return _licenselevel; }
        }

        public string Email
        {
            get { return _email; }
        }

        public string FirstName
        {
            get { return _firstname; }
        }

        public string LastName
        {
            get { return _lastname; }
        }

        public string DevToken
        {
            get { return _devToken; }
        }

        public string Address
        {
            get { return _address; }
        }

        public string City
        {
            get { return _city; }
        }

        public string State
        {
            get { return _state; }
        }

        public string Zipcode
        {
            get { return _zipcode; }
        }

        public string Phone
        {
            get { return _phone; }
        }

        public string UniqueMachineID
        {
            get { return _uniqueMachineID; }
        }
    }

    public class FailureInfo
    {
        #region AlertType enum

        public enum AlertType
        {
            Port,
            None
        } ;

        #endregion

        private AlertType _alert;

        private string _message;
        private WebException _webServiceException;

        public FailureInfo()
        {
        }

        public string Message
        {
            get { return _message; }
            set { _message = value; }
        }

        public AlertType Alert
        {
            get { return _alert; }
            set { _alert = value; }
        }

        public WebException WebServiceException
        {
            get { return _webServiceException; }
            set { _webServiceException = value; }
        }
    }

    /// <summary>
    /// Class that contains specifics about the datastore.
    /// </summary>
    public class DataStoreInfo
    {
        private DateTime _dateTime;
        private string _devId;
        private Form _form;
        private string _productname;
        private string _uniqueClientId;

        public DataStoreInfo(string devId, string productName, string uniqueClientId, DateTime startDateTime, Form form)
        {
            _devId = devId;
            _productname = productName;
            _uniqueClientId = uniqueClientId;
            _dateTime = startDateTime;
            _form = form;
        }

        public Form FormRef
        {
            get { return _form; }
        }

        public DateTime StartDateTime
        {
            get { return _dateTime; }
        }

        public string DevId
        {
            get { return _devId; }
        }

        public string ProductName
        {
            get { return _productname; }
        }

        public string UniqueClientId
        {
            get { return _uniqueClientId; }
        }
    }
}